/**
 * @author Rid King
 * @since 2016-05-20
 * @description 模型，Model是基类
 */

class Model {
  constructor () {
    // 私有事件对象
    this._$events = {}
  }

  /**
   * @description 绑定触发器，外界不能直接访问
   * @param name <String> 事件名称
   * @param fn <Function> 事件回调函数
  */
  $on (name, fn) {
    // 非函数报错
    if (typeof fn !== 'function') {
      throw new TypeError('Second argument for "on" method must be a function.');
    }

    // 加入事件数组
    (this._$events[name] = this._$events[name] || []).push(fn);

    return this
  }

  /**
   * @description 绑定触发器，只执行一次
   * @param name <String> 事件名称
   * @param fn <Function> 事件回调函数
  */
  $once (name, fn) {
    fn._one = true
    return this.$on(name, fn)
  }

  /**
   * @description 绑定触发器，触发器最多为一个
   * @param name <String> 事件名称
   * @param fn <Function> 事件回调函数
  */
  $only (name, fn) {
    // 重置触发器组
    this._$events[name] = []
    // 加入事件数组
    return this.$on(name, fn)
  }

  /**
   * @description 触发指定触发器，带参数触发指定触发器，否则不触发，参数为两个true时，触发所有触发器
   * @param name <String> 事件名称
   * @param args <any> 事件回调参数
  */
  $emit (name, args) {
    let _$events = this._$events
    // 事件不存在
    if (!_$events[name] || !_$events[name].length) {
      return this
    }

    // 参数
    args = [].slice.call(arguments, 1)
    // 事件回调结果
    let results = []
    // 执行事件回调
    _$events[name].forEach(function(fn, i) {
      if (fn) {
        results.push(fn.apply(fn, args))
        if (fn._one) {
            _$events[name].splice(i, 1)
        }
      }
    })

    return results
  }

  /**
   * @description 取消绑定的触发器，带参数删除指定触发器，否则删除所有触发器
   * @param name <String> 事件名称
   * @param fn <Function> 事件回调函数
  */
  $off (name, fn) {
    let _$events = this._$events
    // 删除所有事件
    if (name === '*') {
      this._$events = {}
      return _$events
    }

    // 事件不存在
    if (!_$events[name]) {
      return false
    }

    // 删除单个事件回调
    if (fn) {
      // 非法字符
      if (typeof fn !== 'function') {
        throw new TypeError('Second argument for "off" method must be a function.')
      }

      // 删除事件
      _$events[name] = _$events[name].map(function(fm, i) {
        if (fm === fn) {
          _$events[name].splice(i, 1)
          return false
        }
      })
    }
    // 删除所有回调
    else {
      delete _$events[name]
    }
  }
}

export default Model